Take a look at the following SQL statement and then run it in PHPMyAdmin to create the table (in the my-new-site database):
DROP TABLE IF EXISTS files; CREATE TABLE IF NOT EXISTS files ( fileId int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT, fileName varchar(200) NOT NULL, fileDescription varchar(200) NOT NULL, fileExtension varchar(10) NOT NULL, fileSize int(11) NOT NULL ) ENGINE=InnoDB;
Note that we are going to use this table to keep track of all the images that we add to our blog posts. But it could potentially be used to attach other files to blog posts as well, which is why the table is called 'files' rather than 'images'.
Eventually, this page will allow you to upload image files to your web server. But we won't worry about that yet. For now, we'll just focus on inserting and updating rows in the files table.
Add constants to the config file that point to the uploaded-files dir (for both LIVE and DEV envornments, but you can use the same values for both environments). The constants should look like this:
define("UPLOAD_FOLDER", PROJECT_DIR . "uploaded-files/");
define("SERVER_UPLOAD_FOLDER", $_SERVER['DOCUMENT_ROOT'] . UPLOAD_FOLDER);
Why do we need both UPLOAD_FOLDER and SERVER_UPLOAD_FOLDER? Well, when we are uploading files on the server we'll use a path that is relative to the root directory the computer. But when we display images (that have been uploaded) in the browser, we'll use a path that is relative to the document root directory of the web server.
Add a method named getFileExtenstion() to the FileDataAccess class. Here is the code for it:
// extract the extension from a file name
// Note: In hindsight, I should have used pathinfo() for this (it's a function that's built into PHP)
function getFileExtension($fileName){
$parts = explode(".", $fileName);
//Not sure if we should really throw an exception here!
if(count($parts) < 2){
$this->handle_error("$fileName has no file extension");
}
return array_pop($parts);
}
We could spend some time discussing this code.
Create a file inside the control-panel folder named file-details.php. Then copy this code into it.
Note the hidden fields (fileId, fileName, fileExtension, fileSize). These are all hidden from the user because our code will set their values.
Note that we've added a few variables near the top of the page to help us validate the files being uploaded ($allowed_file_types, and $max_file_size)
Take some time to go through the code and understand it before moving on. Step through the code with the debugger! You can use the page to insert and update records in the files table, but you'll notice it has some issues.
Notice in the file-details.php page, that there are comments that mark off our next steps. To get started, find the comment that says STEP 1.
STEP 1 - Add the following code under the STEP 1 comment. Note that this code runs only if a file is being uploaded.
if($_FILES['upload']['error'] == UPLOAD_ERR_OK){
// get details of the uploaded file and store them in the $file array
$file['fileName'] = $_FILES['upload']['name'];
$file['fileSize'] = $_FILES['upload']['size'];
$file['fileExtension'] = $fda->getFileExtension($file['fileName']);
// set the full path of where the uploaded file should be moved to
$filePath = SERVER_UPLOAD_FOLDER . $file['fileName'];
// move the file from the tmp dir to it's final destination
if( !move_uploaded_file($_FILES['upload']['tmp_name'], $filePath) ){
throw new Exception("Unable to move uploaded file");
}
}
STEP 2 - Once the file has been successfully uploaded and moved to it's final destination, we are going to rename it to use it's fileId. So for example, test.png might become 101.png. The reason for this is that it will prevent files that happen to have the same name from being overwritten. Under this approach, it should be impossible for two files in the upload folder to have the same name. Here is the code:
// Now that the image has been uploaded, let's rename it so that it
// is named by the file id, rather than the original name
$newFileName = $file['fileId'] . "." . $file['fileExtension'];
$newFilePath = SERVER_UPLOAD_FOLDER . $newFileName;
if( !rename($filePath, $newFilePath) ){
throw new Exception("Unable too rename file");
}
STEP 3 - If we are updating an image that is already in our system, we'll want to display, like this:
if($file['fileId'] > 0 && !empty($file['fileExtension'])){
$realFileName = $file['fileId'] . "." . $file['fileExtension'];
echo('<img id="mainImg" src="' . UPLOAD_FOLDER . $realFileName .'" />');
}
STEP 4 - There are various errors that can occur in dealing with the image upload, we'll see how these error messages are generated in the final step. But for now, here is the code to display them:
echo(isset($validationErrors['imageRequired']) ? wrapValidationMsg($validationErrors['imageRequired']) : ""); echo(isset($validationErrors['invalidImageType']) ? wrapValidationMsg($validationErrors['invalidImageType']) : ""); echo(isset($validationErrors['invalidImageSize']) ? wrapValidationMsg($validationErrors['invalidImageSize']) : "");
STEP 5 - Finally, here is the code that validates the file being uploaded. Note that a file upload is not always required. For example, you may want to update the description for a file that you've already entered into the system.
// on inserts, there must be a file uploaded
// http://php.net/manual/en/features.file-upload.errors.php
if($file['fileId'] == 0 && $_FILES['upload']['error'] == UPLOAD_ERR_NO_FILE){
$errors['imageRequired'] = "You must upload an image";
}
if($_FILES['upload']['error'] == UPLOAD_ERR_OK){
// validate the file type
if( !in_array($_FILES['upload']['type'], $allowed_file_types) ){
$errors['invalidImageType'] = "The file must be an image.";
}
// validate the file size
if($_FILES['upload']['size'] > $max_file_size){
$errors['invalidImageSize'] = "The file is too big.";
}
}